require 'digest/sha1'
require 'net/ldap'

class User < ActiveRecord::Base
  include Authentication
  include Authentication::ByPassword
  include Authentication::ByCookieToken

  validates_presence_of     :login
  validates_length_of       :login,    :within => 3..40
  validates_uniqueness_of   :login
  validates_format_of       :login,    :with => Authentication.login_regex, :message => Authentication.bad_login_message

  validates_format_of       :name,     :with => Authentication.name_regex,  :message => Authentication.bad_name_message, :allow_nil => true
  validates_length_of       :name,     :maximum => 100

  validates_presence_of     :email
  validates_length_of       :email,    :within => 6..100 #r@a.wk
  validates_uniqueness_of   :email
  validates_format_of       :email,    :with => Authentication.email_regex, :message => Authentication.bad_email_message

  

  # HACK HACK HACK -- how to do attr_accessible from here?
  # prevents a user from submitting a crafted form that bypasses activation
  # anything else you want your user to change should be added here.
  attr_accessible :login, :email, :name, :password, :password_confirmation



  # Authenticates a user by their login name and unencrypted password.  Returns the user or nil.
  #
  # uff.  this is really an authorization, not authentication routine.  
  # We really need a Dispatch Chain here or something.
  # This will also let us return a human error message.
  #
  #def self.authenticate(login, password)
  #  return nil if login.blank? || password.blank?
  #  u = find_by_login(login.downcase) # need to get the salt
  #  u && u.authenticated?(password) ? u : nil
  #end

  #Alterado o self.authenticate para pegar os dados de login do AD
    def self.authenticate(username,password)
      #passing in the user with the dc attached... you should also be able to use the full CN

      ldap_con = initialize_ldap_con(username + "@ifb.local", password)
      treebase = "DC=ifb,DC=local"   #Alterar essa linha conforme o domínio
      user_filter = Net::LDAP::Filter.eq( "sAMAccountName", username )
      #op_filter = Net::LDAP::Filter.eq( "objectClass", "organizationalPerson" ) #not used

      #ldap will automatically bind when trying to preform a search or modification, so we don't call .bind here.
      #.bind is only if you want to just return true or false, but we want to look up some attributes!

      if ldap_con.search(:base => treebase, :filter => user_filter,
                         :attributes => ['dn','sAMAccountName','displayname','SN','givenName', 'mail']) do |ad_user|
        #try to find the user locally and if they aren't there then create them.
        vlogin = ad_user.samaccountname.to_s.gsub('["','').gsub('"]','')
        vnomecompleto = ad_user.displayname.to_s.to_s.gsub('["','').gsub('"]','')
        vmail = ad_user.mail.to_s.gsub('["','').gsub('"]','')

        local_user = find_by_login(vlogin)
        if !local_user
          local_user = User.new(:login => vlogin, :name => vnomecompleto, :email => vmail)
          local_user.save false #pass false to skip validations
          return local_user
        else
          #They were found in the local database but to keep the local user info sync'd
          #each time we login we update the local db's name and email fields.
          local_user.update_attributes(:name => vnomecompleto, :email => vmail)
          local_user.save false
          return local_user
        end
       end
      else
        return nil #they didn't authenticate to AD
      end
    end

  #Configurador dos dados do AD
  #helper method called from above
    def self.initialize_ldap_con(user_name, password)
      ldap = Net::LDAP.new
      ldap.host = "10.4.0.2"
      #ldap.port = 636 #required for SSL connections, 389 is the default plain text port
      ldap.port = 389
      #ldap.encryption :simple_tls #also required to tell Net:LDAP that we want SSL
      ldap.auth "#{user_name}","#{password}"
      ldap #explicitly return the ldap connection object
    end



  def login=(value)
    write_attribute :login, (value ? value.downcase : nil)
  end

  def email=(value)
    write_attribute :email, (value ? value.downcase : nil)
  end

  
end
